package edu.snake.implement.service;

import edu.snake.core.model.arena.Arena;
import edu.snake.core.model.arena.Position;
import edu.snake.core.model.character.Character;
import edu.snake.implement.model.arena.iterator.SnakeDeploymentArenaIterator;

import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.locks.Lock;

import static edu.snake.implement.model.arena.PositionFactory.getNewPosition;


public class SetToArenaCharacterImpl {

    public void addCharacterToArena(Character character, Arena arena) {
        Lock lock = arena.getLock();
        lock.lock();
        try {
            switch (character.getName()) {
                case SNAKE_HEAD:
                    addSnakeToArena(character, arena);
                    return;
                default:
                    addFrogToArena(character, arena);
            }
        } finally {
            lock.unlock();
        }
    }

    private void addFrogToArena(Character frog, Arena arena) {
        int i = arena.getHeight() * arena.getWidth() * 10;
        while (i > 0) {
            Random random = new Random();
            int randomWidth = random.nextInt(arena.getWidth());
            int randomHeight = random.nextInt(arena.getHeight());
            i--;
            Position position = getNewPosition(randomWidth, randomHeight);
            if (arena.get(position) == null) {
                arena.set(position, frog);
                return;
            }
        }
        throw new RuntimeException("Failed to place character. In the arena of so many characters.");
    }


    private void addSnakeToArena(Character snake, Arena arena) {
        int freeSize = arena.freeSpaceList().size();
        int snakeSize = snake.size();
        if (freeSize > snakeSize) {


            // If two cells remains until the end of the width of the arena, the algorithm shifts it to another cell
            // in height - down and the width of the second cell first
            int widthCorrection = 2;
            int heightCorrection = 0;
            int width = snakeSize % arena.getWidth();
            int temp = arena.getWidth() - widthCorrection;
            if (width >= temp) {
                width = 1;
                ++heightCorrection;
            }
            int height = ((snakeSize / temp)) + heightCorrection;


            Position position = getNewPosition(width, height);
            arena.set(position, snake);
            Iterator<Character> iterator = snake.iterator();
            Iterator<Position> positionIterator = new SnakeDeploymentArenaIterator(position, arena);
            while (iterator.hasNext()) {
                arena.set(positionIterator.next(), iterator.next());
            }
        }
    }
}
